<?php

/**
* class 'thingy' defines a generic parent class from which all other
* database-driven objects will inherit. Because all these objects are
* essentially the same - a database record - the interface will be
* consistent. A class needs only extend thingy, and it gets all this
* magical goodness for free, thusly:
* 
* <code>
* class x extends thingy {
* }
* </code>
* 
* It is assumed that every table will have an ID field which is an 
* auto_increment int field, and is the table index.
* 
* The subclass must then define only those methods which differ from the
* inherited basic get/set methods. The standard get/set methods will be
* defined for each field in the database table.
* 
* <code>
* $x = new x();
* $x->name("Bob"); // Sets the value.
* echo $x->description(); // Returns the value.
* </code>
* 
* A subclass should document its available fields, as well as ordinary
* per-method documentation for additional (or overridden) methods.
* 
* To create a new object, pass in the list of values for that object:
* 
* <code>
* $x = new x( array( name => 'Bob', description => 'Tomato' ) );
* $x->save(); // Saves object to the database.
* </code>
* 
* To load an existing object from the database, pass in the ID number of
* that object:
* 
* <code>
* $x = new x( array( ID => 12 ) );
* </code>
* 
*/

class thingy {

function __construct( $args = array() ) {

    // Do we have a database handle?
    global $db;
    valid_handle($db);
    
    $this->table = TABLE_PREFIX . get_class( $this );
    $q = $db->safe_query('show columns from %s', $this->table );
    $c = $db->get_results( $q );

    foreach ($c as $col) {
        if ($col->Field != 'ID') {
            $fields[] = $col->Field;
        }
    }
    $this->fields = $fields;


    if (isset ($args['ID'])) {
        load_obj($this, $args['ID']);
    } else {
        // Creating a new object.
            foreach ($this->fields as $field) {
                $this->{"_$field"} = $args["$field"];
            }
            $this->_modified = 1;
    }
}

/**
* Save the object to the database, if any of the values have changed.
*
* <code>
* $obj->save();
* </cod>
*/
function save() {
    global $db;
    return $db->save($this);
}

/**
* Update the values in the database
* 
* @param array $attribs Array of fields which you want to modify
*
* <code>
* $obj->update( array ( name => 'Bob', description => 'tomato' ) ) ;
* </code>
*/
function update($attribs) {
    foreach ($attribs as $key => $value) {
        if ( in_array( $key, $this->fields ) ) {
            $this->$key($value);
        }
    }
    $this->save();
}

/**
* Permanently deletes the object from the database
*
* @param int $ID ID number of object to be deleted
* 
* Please remember that once you've deleted an object, you really should
* quit using it, because it's not valid any more.
*
* <code>
* $page->delete();
* </code>
*/
function delete() {
    global $db;
    $db->delete($this->table,$this->ID());
}

/**
* Generic get/set methods for attributes of the object.
* 
* @param string $method The name of the method/attribute to call
* @param array $args List of arguments to pass to this method
*
* Calling one of these objects without arguments will return the value
* of that attribute. Calling it with an argument will set the attribute
* to that value:
*
* <code>
* $desc = $story->description();
* $story->title("Man bites dog");
* </code>
*
* Remember to save an object after modifying an attribute.
*/
function __call($method, $args) {
    if ($method == 'id' || $method == 'ID') {
        return $this->_id;
    } else if (in_array($method, $this->fields)) {
           return getset($this, $method, $args);
    } else {
           print "Invalid method \"$method\" called on an object of type " 
            . get_class($this);
           exit();
    }
}

}

// vim: filetype=php
?>
